home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / editors / mjovesrc.zoo / c.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  17KB  |  752 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. /* Contains commands for C mode.  Paren matching routines are in here. */
  9.  
  10. #include "jove.h"
  11. #include "re.h"
  12. #include "ctype.h"
  13. #include "disp.h"
  14.  
  15. private void
  16. #ifdef    CMT_FMT
  17.     FillComment proto((char *format)),
  18. #endif
  19.     FindMatch proto((int));
  20.  
  21. private int
  22. backslashed(lp, cpos)
  23. register char    *lp;
  24. register int    cpos;
  25. {
  26.     register int    cnt = 0;
  27.  
  28.     while (cpos > 0 && lp[--cpos] == '\\')
  29.         cnt += 1;
  30.     return (cnt % 2);
  31. }
  32.  
  33. private char    *p_types = "(){}[]";
  34. private int    mp_kind;
  35. #define MP_OKAY        0
  36. #define MP_MISMATCH    1
  37. #define MP_UNBALANCED    2
  38. #define MP_INCOMMENT    3
  39.  
  40. void
  41. mp_error()
  42. {
  43.     switch (mp_kind) {
  44.     case MP_MISMATCH:
  45.         message("[Mismatched parentheses]");
  46.         break;
  47.  
  48.     case MP_UNBALANCED:
  49.         message("[Unbalanced parenthesis]");
  50.         break;
  51.  
  52.     case MP_INCOMMENT:
  53.         message("[Inside a comment]");
  54.         break;
  55.  
  56.     case MP_OKAY:
  57.     default:
  58.         return;
  59.     }
  60.     rbell();
  61. }
  62.  
  63. /* Search from the current position for the paren that matches p_type.
  64.    Search in the direction dir.  If can_mismatch is YES then it is okay
  65.    to have mismatched parens.  If stop_early is YES then when an open
  66.    paren is found at the beginning of a line, it is assumed that there
  67.    is no point in backing up further.  This is so when you hit tab or
  68.    LineFeed outside, in-between procedure/function definitions, it won't
  69.    sit there searching all the way to the beginning of the file for a
  70.    match that doesn't exist.  {forward,backward}-s-expression are the
  71.    only ones that insist on getting the "true" story. */
  72.  
  73. Bufpos *
  74. m_paren(p_type, dir, can_mismatch, can_stop)
  75. int    p_type;
  76. register int    dir;
  77. int    can_mismatch;
  78. int    can_stop;
  79. {
  80.     static Bufpos    ret;
  81.     Bufpos    savedot,
  82.         *sp;
  83.     struct RE_block    re_blk;
  84.     int    count = 0;
  85.     register char    *lp,
  86.             c;
  87.     char    p_match,
  88.         re_str[128],
  89.         *cp,
  90.         quote_c = 0;
  91.     register int    c_char;
  92.     int    in_comment = -1,
  93.         stopped = NO;
  94.  
  95.     swritef(re_str, sizeof(re_str), "[(){}[\\]%s]",
  96.         (MajorMode(CMODE)) ? "/\"'" : "\"");
  97.     REcompile(re_str, YES, &re_blk);
  98.     if ((cp = strchr(p_types, p_type)) == NULL)
  99.         complain("[Cannot match %c's]", p_type);
  100.     p_match = cp[dir];
  101.     DOTsave(&savedot);
  102.  
  103.     /* To make things a little faster I avoid copying lines into
  104.        linebuf by setting curline and curchar by hand.  Warning:
  105.        this is slightly to very risky.  When I did this there were
  106.        lots of problems with procedures that expect the contents of
  107.        curline to be in linebuf. */
  108.     do {
  109.         sp = docompiled(dir, &re_blk);
  110.         if (sp == NULL)
  111.             break;
  112.         lp = lbptr(sp->p_line);
  113.  
  114.         curline = sp->p_line;
  115.         curchar = sp->p_char;    /* here's where I cheat */
  116.  
  117.         c_char = curchar;
  118.         if (dir == FORWARD)
  119.             c_char -= 1;
  120.         if (backslashed(lp, c_char))
  121.             continue;
  122.         c = lp[c_char];
  123.         /* check if this is a comment (if we're not inside quotes) */
  124.         if (quote_c == 0 && c == '/') {
  125.             int    new_ic = in_comment;
  126.  
  127.             /* close comment */
  128.             if ((c_char != 0) && lp[c_char - 1] == '*') {
  129.                 new_ic = (dir == FORWARD) ? NO : YES;
  130.                 if (new_ic == NO && in_comment == -1) {
  131.                     count = 0;
  132.                     quote_c = 0;
  133.                 }
  134.             } else if (lp[c_char + 1] == '*') {
  135.                 new_ic = (dir == FORWARD) ? YES : NO;
  136.                 if (new_ic == NO && in_comment == -1) {
  137.                     count = 0;
  138.                     quote_c = 0;
  139.                 }
  140.             }
  141.             in_comment = new_ic;
  142.         }
  143.         if (in_comment == YES)
  144.             continue;
  145.         if (c == '"' || c == '\'') {
  146.             if (quote_c == c)
  147.                 quote_c = 0;
  148.             else if (quote_c == 0)
  149.                 quote_c = c;
  150.         }
  151.         if (quote_c != 0)
  152.             continue;
  153.         if (jisopenp(c)) {
  154.             count += dir;
  155.             if (c_char == 0 && can_stop == YES && count >= 0) {
  156.                 stopped = YES;
  157.                 break;
  158.             }
  159.         } else if (jisclosep(c))
  160.             count -= dir;
  161.     } while (count >= 0);
  162.  
  163.     ret.p_line = curline;
  164.     ret.p_char = curchar;
  165.  
  166.     curline = savedot.p_line;
  167.     curchar = savedot.p_char;    /* here's where I undo it */
  168.  
  169.     if (count >= 0)
  170.         mp_kind = MP_UNBALANCED;
  171.     else if (c != p_match)
  172.         mp_kind = MP_MISMATCH;
  173.     else
  174.         mp_kind = MP_OKAY;
  175.  
  176.     /* If we stopped (which means we were allowed to stop) and there
  177.        was an error, we clear the error so no error message is printed.
  178.        An error should be printed ONLY when we are sure about the fact,
  179.        namely we didn't stop prematurely HOPING that it was the right
  180.        answer. */
  181.     if (stopped && mp_kind != MP_OKAY) {
  182.         mp_kind = MP_OKAY;
  183.         return NULL;
  184.     }
  185.     if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
  186.         return &ret;
  187.     return NULL;
  188. }
  189.  
  190. private void
  191. do_expr(dir, skip_words)
  192. register int    dir;
  193. int    skip_words;
  194. {
  195.     register char    c,
  196.             syntax = (dir == FORWARD) ? C_BRA : C_KET;
  197.  
  198.     if (dir == BACKWARD)
  199.         b_char(1);
  200.     c = linebuf[curchar];
  201.     for (;;) {
  202.         if (!skip_words && ismword(c)) {
  203.             WITH_TABLE(curbuf->b_major)
  204.             if (dir == FORWARD)
  205.                 f_word(1);
  206.             else
  207.                 b_word(1);
  208.             END_TABLE();
  209.             break;
  210.         } else if (has_syntax(c, syntax)) {
  211.             FindMatch(dir);
  212.             break;
  213.         }
  214.         f_char(dir);
  215.         if (eobp() || bobp())
  216.             return;
  217.         c = linebuf[curchar];
  218.     }
  219. }
  220.  
  221. void
  222. FSexpr()
  223. {
  224.     register int    num = arg_value();
  225.  
  226.     if (num < 0) {
  227.         set_arg_value(-num);
  228.         BSexpr();
  229.     }
  230.     while (--num >= 0)
  231.         do_expr(FORWARD, NO);
  232. }
  233.  
  234. void
  235. FList()
  236. {
  237.     register int    num = arg_value();
  238.  
  239.     if (num < 0) {
  240.         set_arg_value(-num);
  241.         BList();
  242.     }
  243.     while (--num >= 0)
  244.         do_expr(FORWARD, YES);
  245. }
  246.  
  247. void
  248. BSexpr()
  249. {
  250.     register int    num = arg_value();
  251.  
  252.     if (num < 0) {
  253.         negate_arg_value();
  254.         FSexpr();
  255.     }
  256.     while (--num >= 0)
  257.         do_expr(BACKWARD, NO);
  258. }
  259.  
  260. void
  261. BList()
  262. {
  263.     register int    num = arg_value();
  264.  
  265.     if (num < 0) {
  266.         negate_arg_value();
  267.         FList();
  268.     }
  269.     while (--num >= 0)
  270.         do_expr(BACKWARD, YES);
  271. }
  272.  
  273. void
  274. BUpList()
  275. {
  276.     Bufpos    *mp;
  277.     char    c = (MajorMode(CMODE) ? '}' : ')');
  278.  
  279.     mp = m_paren(c, BACKWARD, NO, YES);
  280.     if (mp == NULL)
  281.         mp_error();
  282.     else
  283.         SetDot(mp);
  284. }
  285.  
  286. void
  287. FDownList()
  288. {
  289.     Bufpos    *sp;
  290.     char    *sstr = MajorMode(CMODE) ? "[{([\\])}]" : "[()]";
  291.  
  292.     sp = dosearch(sstr, FORWARD, YES);
  293.     if (sp == NULL || has_syntax(lcontents(sp->p_line)[sp->p_char - 1], C_KET))
  294.         complain("[No contained expression]");
  295.     SetDot(sp);
  296. }
  297.  
  298. /* Move to the matching brace or paren depending on the current position
  299.    in the buffer. */
  300.  
  301. private void
  302. FindMatch(dir)
  303. int    dir;
  304. {
  305.     register Bufpos    *bp;
  306.     register char    c = linebuf[curchar];
  307.  
  308.     if ((strchr(p_types, c) == NULL) ||
  309.         (backslashed(linebuf, curchar)))
  310.         complain((char *)NULL);
  311.     if (dir == FORWARD)
  312.         f_char(1);
  313.     bp = m_paren(c, dir, YES, NO);
  314.     if (dir == FORWARD)
  315.         b_char(1);
  316.     if (bp != NULL)
  317.         SetDot(bp);
  318.     mp_error();    /* if there is an error the user wants to
  319.                know about it */
  320. }
  321.  
  322. #define ALIGN_ARGS    (-1)
  323.  
  324. /* If CArgIndent == ALIGN_ARGS then the indentation routine will
  325.    indent a continued line by lining it up with the first argument.
  326.    Otherwise, it will indent CArgIndent characters past the indent
  327.    of the first line of the procedure call. */
  328.  
  329. int    CArgIndent = ALIGN_ARGS;
  330.  
  331. /* indent for C code */
  332. Bufpos *
  333. c_indent(brace)
  334. int    brace;
  335. {
  336.     Bufpos    *bp;
  337.     int    new_indent = 0,
  338.         current_indent,
  339.         increment;
  340.  
  341.     if (brace == NO)
  342.         increment = CIndIncrmt;
  343.     else
  344.         increment = 0;
  345.     /* Find matching paren, which may be a mismatch now.  If it
  346.        is not a matching curly brace then it is a paren (most likely).
  347.        In that case we try to line up the arguments to a procedure
  348.        or inside an of statement. */
  349.     if ((bp = m_paren('}', BACKWARD, YES, YES)) != NULL) {
  350.         Bufpos    save;
  351.         int    matching_indent;
  352.  
  353.         DOTsave(&save);
  354.         SetDot(bp);        /* go to matching paren */
  355.         ToIndent();
  356.         matching_indent = calc_pos(linebuf, curchar);
  357.         SetDot(bp);
  358.         switch (linebuf[curchar]) {
  359.         case '{':
  360.             new_indent = matching_indent;
  361.             if (!bolp()) {
  362.                 b_char(1);
  363.                 /* If we're not within the indent then we
  364.                    can assume that there is either a C keyword
  365.                    line DO on the line before the brace, or
  366.                    there is a parenthesized expression.  If
  367.                    that's the case we want to go backward
  368.                    over that to the beginning of the expression
  369.                    so that we can get the correct in